package com.dajia.hefei.nbiot;

import com.dajia.hefei.nbiot.bean.Optional;
import com.dajia.hefei.nbiot.bean.Required;
import com.dajia.hefei.nbiot.bean.request.*;
import com.dajia.hefei.nbiot.bean.response.*;
import com.dajia.hefei.nbiot.util.*;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class NbiotApi {

    /**
     * 初始化加载https相关证书
     */
    public static void init(String certPath, String certPwd, String caPath, String caPwd) {
        if (null == HttpsUtil.getClient()) {
            try {
                init(NbiotApi.class.getClassLoader().getResourceAsStream(certPath), certPwd, NbiotApi.class.getClassLoader().getResourceAsStream(caPath), caPwd);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("init", e);
            }
        }
    }

    /**
     * 初始化加载https相关证书
     */
    public static void init(InputStream certPath, String certPwd, InputStream caPath, String caPwd) {
        if (null == HttpsUtil.getClient()) {
            try {
                HttpsUtil.initSSLConfigForTwoWay(certPath, certPwd.toCharArray(), caPath, caPwd.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("init", e);
            }
        }
    }

    /**
     * 构造请求头
     */
    private static Map<String, String> buildHeader(String appId, String secret) {
        ResponseForQueryAccessToken accessToken = getToken(appId, secret);
        return null != accessToken ? new HashMap<String, String>() {{
            put(Constant.HEADER_APP_KEY, appId);
            put(Constant.HEADER_APP_AUTH, "Bearer" + " " + accessToken.getAccessToken());
        }} : null;
    }

    /**
     * 构造请求参数
     */
    private static Map<String, String> buildParam(Object param) {
        Map<String, String> queryParam = null;
        if (null != param) {
            Gson gson = new Gson();
            queryParam = gson.fromJson(gson.toJson(param), Map.class);
        }
        return queryParam;
    }

    /**
     * 构造请求结果
     */
    private static <T> T buildResult(StreamClosedHttpResponse httpResponse, Class<T> cls) {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        if (null != httpResponse) {
            log.info("{}: \nstatus:{}\ncontent:{}", stackTrace[2].getMethodName(), httpResponse.getStatusLine(), httpResponse.getContent());
            if (httpResponse.success()) {
                T result = JsonUtil.toObject(httpResponse.getContent(), cls);
                if (null != result) {
                    return result;
                }
            }
        }
        log.info("{}, result is null", stackTrace[2].getMethodName());
        return null;
    }

    /**
     * 构造请求结果状态
     */
    private static boolean buildResult(StreamClosedHttpResponse httpResponse) {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        if (null != httpResponse) {
            log.info("{}: \nstatus:{}\ncontent:{}", stackTrace[2].getMethodName(), httpResponse.getStatusLine(), httpResponse.getContent());
            if (httpResponse.success()) {
                BaseResponse result = JsonUtil.toObject(httpResponse.getContent(), BaseResponse.class);
                return null != result && result.success();
            }
        }
        log.info("{}, result is null", stackTrace[2].getMethodName());
        return false;
    }

    /**
     * 对象转换
     */
    private static <T> T content2Target(String content, Class<T> cls) {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        log.info("{}: content={}", stackTrace[2].getMethodName(), content);
        return StringUtils.isNotBlank(content) ? JsonUtil.toObject(content, cls) : null;
    }

    /**
     * 2.1.1 鉴权
     */
    public static ResponseForQueryAccessToken getToken(@Required String appId, @Required String secret) {
        log.error("getToken: appId={}", appId);
        if (null == HttpsUtil.getClient()) {
            log.error("https client 没有初始化，请先调用Nbiot.init进行初始化!!!");
            return null;
        }

        if (StringUtils.isAnyBlank(appId, secret)) {
            log.error("appId or secret is empty!!!");
            return null;
        }

        ResponseForQueryAccessToken accessToken = CacheUtil.get(appId + secret, ResponseForQueryAccessToken.class);
        if (null != accessToken) {
            log.info("getToken from cache: " + accessToken);
            return accessToken;
        }

        StreamClosedHttpResponse httpResponse = HttpsUtil.doPostFormUrlEncodedGetStatusLine(
                Constant.APP_AUTH,
                new HashMap<String, String>() {{
                    put("appId", appId);
                    put("secret", secret);
                }});

        accessToken = buildResult(httpResponse, ResponseForQueryAccessToken.class);
        if (null != accessToken && accessToken.success()) {
            CacheUtil.set(appId + secret, accessToken, (int) (accessToken.getExpiresIn() * 0.9));
            return accessToken;
        }
        log.error("getToken, result is null: appId={}", appId);
        return null;
    }

    /**
     * 2.1.2 刷新token
     */
    public static ResponseForQueryAccessToken refreshToken(@Required String appId, @Required String secret, @Required String refreshToken) {
        log.info("refreshToken:appid={}, refreshToken={}", appId, refreshToken);
        if (!StringUtils.isAnyBlank(appId, secret, refreshToken)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.REFRESH_TOKEN,
                    JsonUtil.toJson(new HashMap<String, String>() {{
                        put("appId", appId);
                        put("secret", secret);
                        put("refreshToken", refreshToken);
                    }}));

            ResponseForQueryAccessToken result = buildResult(httpResponse, ResponseForQueryAccessToken.class);
            if (null != result && result.success()) {
                CacheUtil.set(appId + secret, result, (int) (result.getExpiresIn() * 0.9));
                return result;
            }
        }
        log.error("refreshToken, result is null: appid={}, refreshToken={}", appId, refreshToken);
        return null;
    }

    /**
     * 2.2.1 注册直连设备
     */
    public static ResponseForRegisterDirectlyConnectedDevice registerDirectlyConnectedDevice(@Required String appId, @Required String secret, @Required RequestForRegisterDirectlyConnectedDevice param) {
        log.info("registerDirectlyConnectedDevice: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.REGISTER_DEVICE,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForRegisterDirectlyConnectedDevice.class);
        }
        log.info("registerDirectlyConnectedDevice, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.2.2 刷新设备密钥
     */
    public static ResponseForRefreshVerifyCode refreshVerifyCode(@Required String appId, @Required String secret, @Required RequestForRefreshVerifyCode param) {
        log.info("refreshVerifyCode: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJson(
                    Constant.REGISTER_DEVICE + "/" + param.getDeviceId(),
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForRefreshVerifyCode.class);
        }
        log.info("refreshVerifyCode, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.2.3 修改设备信息
     */
    public static boolean modifyDeviceInfo(@Required String appId, @Required String secret, @Required String deviceId, @Required RequestForModifyDeviceInfo updateDeviceInfo) {
        log.info("modifyDeviceInfo: appId={}, deviceId={}, updateDeviceInfo={}", appId, deviceId, updateDeviceInfo);
        if (!StringUtils.isAnyBlank(appId, secret, deviceId) && null != updateDeviceInfo) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJsonGetStatusLine(
                    Constant.MODIFY_DEVICE_INFO + "/" + deviceId,
                    buildHeader(appId, secret),
                    new Gson().toJson(updateDeviceInfo));

            return buildResult(httpResponse);
        }
        log.info("modifyDeviceInfo, result is null: appId={}, deviceId={}, updateDeviceInfo={}", appId, deviceId, updateDeviceInfo);
        return false;
    }

    /**
     * 2.2.4 删除直连设备
     * cascade：仅当设备下连接了非直连设备时生效。true，级联删除。false，删除直连设备，但是不删其下的非直连设备，并将非直连设备的属性变为直连设备属性。
     */
    public static boolean deleteDirectlyConnectedDevice(@Required String appId, @Required String secret, @Required String deviceId, @Optional Boolean cascade) {
        log.info("deleteDirectlyConnectedDevice: appId={}, deviceId={}, cascade={}", appId, deviceId, cascade);
        if (!StringUtils.isAnyBlank(appId, secret, deviceId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteGetStatusLine(
                    Constant.DELETE_DEVICE + "/" + deviceId + (null == cascade ? "" : ("?cascade=" + cascade)),
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("deleteDirectlyConnectedDevice, result is null: appId={}, deviceId={}, cascade={}", appId, deviceId, cascade);
        return false;
    }

    /**
     * 2.2.5 查询设备激活状态
     */
    public static boolean queryDeviceActivationStatus(@Required String appId, @Required String secret, @Required String deviceId) {
        log.info("queryDeviceActivationStatus: appId={}, deviceId={}", appId, deviceId);
        if (!StringUtils.isAnyBlank(appId, secret, deviceId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.QUERY_DEVICE_ACTIVATION_STATUS + "/" + deviceId,
                    null,
                    buildHeader(appId, secret));

            ResponseForQueryDeviceActivationStatus status = buildResult(httpResponse, ResponseForQueryDeviceActivationStatus.class);
            return null != status && status.success() && status.getActivated();
        }
        log.info("queryDeviceActivationStatus, result is null: appId={}, deviceId={}", appId, deviceId);
        return false;
    }

    /**
     * 2.3.1 创建批量任务
     */
    public static ResponseForCreateTasks createTasks(@Required String appId, @Required String secret, @Required RequestForCreateTasks param) {
        log.info("createTasks: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.BATCHTASK,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateTasks.class);
        }
        log.info("createTasks, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.3.2 查询单个任务信息
     */
    public static ResponseForQuerySingleTask querySingleTask(@Required String appId, @Required String secret, @Required RequestForQuerySingleTask param) {
        log.info("querySingleTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.BATCHTASK + "/" + param.getTaskId() + (StringUtils.isBlank(param.getSelect()) ? "" : ("?select=" + param.getSelect())),
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQuerySingleTask.class);
        }
        log.info("querySingleTask, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.3.3 查询任务详情信息
     */
    public static ResponseForQueryTaskDetail queryTaskDetail(@Required String appId, @Required String secret, @Required RequestForQueryTaskDetail param) {
        log.info("queryTaskDetail: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.BATCHTASK_DETAIL,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryTaskDetail.class);
        }
        log.info("queryTaskDetail, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.4.1 创建规则
     */
    public static ResponseForCreateRule createRule(@Required String appId, @Required String secret, @Required RequestForCreateRule param) {
        log.info("createRule: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.RULES,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateRule.class);
        }
        log.info("createRule, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.4.2 更新规则
     */
    public static ResponseForUpdateRule updateRule(@Required String appId, @Required String secret, @Required RequestForUpdateRule param) {
        log.info("updateRule: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJsonGetStatusLine(
                    Constant.RULES,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForUpdateRule.class);
        }
        log.info("updateRule, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.4.3 删除规则
     */
    public static boolean deleteRule(@Required String appId, @Required String secret, @Required String ruleId) {
        log.info("deleteRule: appId={}, ruleId={}", appId, ruleId);
        if (!StringUtils.isAnyBlank(appId, secret, ruleId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteGetStatusLine(
                    Constant.RULES + "/" + ruleId,
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("createRule, result is null: appId={}, ruleId={}", appId, ruleId);
        return false;
    }

    /**
     * 2.4.4 查找规则
     */
    public static ResponseForQueryRule queryRule(@Required String appId, @Required String secret, @Required RequestForQueryRule param) {
        log.info("queryRule: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.RULES,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryRule.class);
        }
        log.info("queryRule, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.4.5 修改规则状态
     */
    public static boolean modifyRuleStatus(@Required String appId, @Required String secret, @Required RequestForModifyRuleStatus param) {
        log.info("modifyRuleStatus: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutGetStatusLine(
                    String.format(Constant.MODIFY_RULES, param.getRuleId(), param.getStatus().toString()),
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("modifyRuleStatus, result is null: appId={}, param={}", appId, param);
        return false;
    }

    /**
     * 2.4.6 批量修改规则状态
     */
    public static ResponseForModifyRulesStatus modifyRulesStatus(@Required String appId, @Required String secret, @Required RequestForModifyRulesStatus param) {
        log.info("modifyRulesStatus: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJsonGetStatusLine(
                    Constant.BATCH_MODIFY_RULES,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForModifyRulesStatus.class);
        }
        log.info("modifyRulesStatus: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.5.1 订阅平台业务数据
     */
    public static ResponseForSubBussinessData subBussinessData(@Required String appId, @Required String secret, @Required RequestForSubBussinessData param) {
        log.info("subBussinessData: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.SUB_DATA,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForSubBussinessData.class);
        }
        log.info("subBussinessData: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.5.2 订阅平台管理数据
     */
    public static boolean subManageData(@Required String appId, @Required String secret, @Required RequestForSubManageData param) {
        log.info("subManageData: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.SUB_MANAGE,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse);
        }
        log.info("subManageData: appId={}, param={}", appId, param);
        return false;
    }

    /**
     * 2.5.3 查询单个订阅
     */
    public static ResponseForQuerySub querySub(@Required String appId, @Required String secret, @Required String subscriptionId) {
        log.info("querySub: appId={}, subscriptionId={}", appId, subscriptionId);
        if (!StringUtils.isAnyBlank(appId, secret, subscriptionId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.SUB_DATA + "/" + subscriptionId,
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQuerySub.class);
        }
        log.info("querySub: appId={}, subscriptionId={}", appId, subscriptionId);
        return null;
    }

    /**
     * 2.5.4 批量查询订阅
     */
    public static ResponseForQuerySubs querySubs(@Required String appId, @Required String secret, @Optional RequestForQuerySubs param) {
        log.info("querySubs: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.SUB_DATA,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQuerySubs.class);
        }
        log.info("querySubs: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.5.5 删除单个订阅
     */
    public static boolean deleteSub(@Required String appId, @Required String secret, @Required String subscriptionId) {
        log.info("deleteSub: appId={}, subscriptionId={}", appId, subscriptionId);
        if (!StringUtils.isAnyBlank(appId, secret, subscriptionId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteGetStatusLine(
                    Constant.SUB_DATA + "/" + subscriptionId,
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("deleteSub: appId={}, subscriptionId={}", appId, subscriptionId);
        return false;
    }

    /**
     * 2.5.6 批量删除订阅
     */
    public static boolean deleteSubs(@Required String appId, @Required String secret, @Optional RequestForDeleteSubs param) {
        log.info("deleteSubs: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteWithParasGetStatusLine(
                    Constant.SUB_DATA,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("deleteSubs: appId={}, param={}", appId, param);
        return false;
    }

    /**
     * 2.6.1 注册设备通知
     */
    public static ResponseForSubscribeOfDeviceAdded subscribeOfDeviceAdded(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceAdded.class);
    }

    /**
     * 2.6.2 设备信息变化通知
     */
    public static ResponseForSubscribeOfDeviceInfoChanged subscribeOfDeviceInfoChanged(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceInfoChanged.class);
    }

    /**
     * 2.6.3 设备数据变化通知
     */
    public static ResponseForSubscribeOfDeviceDataChanged subscribeOfDeviceDataChanged(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceDataChanged.class);
    }

    /**
     * 2.6.4 批量设备数据变化通知
     */
    public static ResponseForSubscribeOfDeviceDatasChanged subscribeOfDeviceDatasChanged(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceDatasChanged.class);
    }

    /**
     * 2.6.5 设备服务信息变化通知
     */
    public static ResponseForSubscribeOfServiceInfoChanged subscribeOfServiceInfoChanged(String content) {
        return content2Target(content, ResponseForSubscribeOfServiceInfoChanged.class);
    }

    /**
     * 2.6.6 删除设备通知
     */
    public static ResponseForSubscribeOfDeviceDeleted subscribeOfDeviceDeleted(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceDeleted.class);
    }

    /**
     * 2.6.7 设备消息确认通知
     */
    public static ResponseForSubscribeOfMessageConfirm subscribeOfMessageConfirm(String content) {
        return content2Target(content, ResponseForSubscribeOfMessageConfirm.class);
    }

    /**
     * 2.6.8 设备命令响应通知
     */
    public static ResponseForSubscribeOfCommandRsp subscribeOfCommandRsp(String content) {
        return content2Target(content, ResponseForSubscribeOfCommandRsp.class);
    }

    /**
     * 2.6.9 设备事件通知
     */
    public static ResponseForSubscribeOfDeviceEvent subscribeOfDeviceEvent(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceEvent.class);
    }

    /**
     * 2.6.10 增加设备模型通知
     */
    public static ResponseForSubscribeOfDeviceModelAdded subscribeOfDeviceModelAdded(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceModelAdded.class);
    }

    /**
     * 2.6.11 删除设备模型通知
     */
    public static ResponseForSubscribeOfDeviceModelDeleted subscribeOfDeviceModelDeleted(String content) {
        return content2Target(content, ResponseForSubscribeOfDeviceModelDeleted.class);
    }

    /**
     * 2.6.12 规则事件通知
     */
    public static ResponseForSubscribeOfRuleEvent subscribeOfRuleEvent(String content) {
        return content2Target(content, ResponseForSubscribeOfRuleEvent.class);
    }

    /**
     * 2.6.13 软件升级状态变更通知
     */
    public static ResponseForSubscribeOfSwUpgradeStateChangeNotify subscribeOfSwUpgradeStateChangeNotify(String content) {
        return content2Target(content, ResponseForSubscribeOfSwUpgradeStateChangeNotify.class);
    }

    /**
     * 2.6.14 软件升级结果变更通知
     */
    public static ResponseForSubscribeOfSwUpgradeResultChangeNotify subscribeOfSwUpgradeResultChangeNotify(String content) {
        return content2Target(content, ResponseForSubscribeOfSwUpgradeResultChangeNotify.class);
    }

    /**
     * 2.6.15 固件升级状态变更通知
     */
    public static ResponseForSubscribeOfFwUpgradeStateChangeNotify subscribeOfFwUpgradeStateChangeNotify(String content) {
        return content2Target(content, ResponseForSubscribeOfFwUpgradeStateChangeNotify.class);
    }

    /**
     * 2.6.16 固件升级结果变更通知
     */
    public static ResponseForSubscribeOfFwUpgradeResultChangeNotify subscribeOfFwUpgradeResultChangeNotify(String content) {
        return content2Target(content, ResponseForSubscribeOfFwUpgradeResultChangeNotify.class);
    }


    /**
     * 2.7.1 创建设备命令
     */
    public static ResponseForCreateDeviceCommand createDeviceCommand(@Required String appId, @Required String secret, @Required RequestForCreateDeviceCommand param) {
        log.info("createDeviceCommand: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.POST_ASYN_CMD,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateDeviceCommand.class);
        }
        log.info("createDeviceCommand: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.7.2 查询设备命令
     */
    public static ResponseForQueryDeviceCommand queryDeviceCommand(@Required String appId, @Required String secret, @Optional RequestForQueryDeviceCommand param) {
        log.info("queryDeviceCommand: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.POST_ASYN_CMD,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceCommand.class);
        }
        log.info("queryDeviceCommand: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.7.3 修改设备命令
     */
    public static ResponseForModifyDeviceCommand modifyDeviceCommand(@Required String appId, @Required String secret, @Required RequestForModifyDeviceCommand param) {
        log.info("modifyDeviceCommand: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJsonGetStatusLine(
                    Constant.POST_ASYN_CMD + "/" + param.getDeviceCommandId(),
                    buildHeader(appId, secret),
                    new Gson().toJson(param.getBody()));

            return buildResult(httpResponse, ResponseForModifyDeviceCommand.class);
        }
        log.info("modifyDeviceCommand: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.7.4 创建设备命令撤销任务
     */
    public static ResponseForCreateDeviceCommandCancelTask createDeviceCommandCancelTask(@Required String appId, @Required String secret, @Required RequestForCreateDeviceCommandCancelTask param) {
        log.info("createDeviceCommandCancelTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.CREATE_DEVICECMD_CANCEL_TASK,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateDeviceCommandCancelTask.class);
        }
        log.info("createDeviceCommandCancelTask: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.7.5 查询设备命令撤销任务
     */
    public static ResponseForQueryDeviceCommandCancelTask queryDeviceCommandCancelTask(@Required String appId, @Required String secret, @Optional RequestForQueryDeviceCommandCancelTask param) {
        log.info("queryDeviceCommandCancelTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.CREATE_DEVICECMD_CANCEL_TASK,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceCommandCancelTask.class);
        }
        log.info("queryDeviceCommandCancelTask: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.8.1 查询单个设备信息
     */
    public static ResponseForQueryDevice queryDevice(@Required String appId, @Required String secret, @Required RequestForQueryDevice param) {
        log.info("queryDevice: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.QUERY_DEVICES + "/" + param.getDeviceId() + (StringUtils.isBlank(param.getSelect()) ? "" : ("?select=" + param.getSelect())),
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDevice.class);
        }
        log.info("queryDevice: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.8.2 批量查询设备信息列表
     */
    public static ResponseForQueryDevices queryDevices(@Required String appId, @Required String secret, @Required RequestForQueryDevices param) {
        log.info("queryDevices: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.QUERY_DEVICES,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDevices.class);
        }
        log.info("queryDevices: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.8.3 查询设备历史数据
     */
    public static ResponseForQueryHistoryDivice queryHistoryDivice(@Required String appId, @Required String secret, @Required RequestForQueryHistoryDevice param) {
        log.info("queryHistoryDivice: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret) && null != param) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.QUERY_DEVICE_HISTORY_DATA,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryHistoryDivice.class);
        }
        log.info("queryHistoryDivice: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.8.4 查询设备服务能力
     */
    public static ResponseForQueryDeviceCapabilities queryDeviceCapabilities(@Required String appId, @Required String secret, @Optional RequestForQueryDeviceCapabilities param) {
        log.info("queryDeviceCapabilities: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.QUERY_DEVICE_CAPABILITIES,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceCapabilities.class);
        }
        log.info("queryDeviceCapabilities, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.1 创建设备组
     */
    public static ResponseForCreateDeviceGroup createDeviceGroup(@Required String appId, @Required String secret, @Optional RequestForCreateDeviceGroup param) {
        log.info("createDeviceGroup: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.DEV_GROUP,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateDeviceGroup.class);
        }
        log.info("createDeviceGroup, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.2 删除设备组
     */
    public static boolean deleteDeviceGroup(@Required String appId, @Required String secret, @Required String devGroupId, @Optional String accessAppId) {
        log.info("deleteDeviceGroup: appId={}, devGroupId={}, accessAppId={}", appId, devGroupId, accessAppId);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteGetStatusLine(
                    Constant.DEV_GROUP + "/" + devGroupId + (StringUtils.isBlank(accessAppId) ? "" : ("?accessAppId=" + accessAppId)),
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("deleteDeviceGroup: appId={}, devGroupId={}, accessAppId={}", appId, devGroupId, accessAppId);
        return false;
    }

    /**
     * 2.9.3 修改设备组
     */
    public static ResponseForModifyDeviceGroup modifyDeviceGroup(@Required String appId, @Required String secret, @Optional RequestForModifyDeviceGroup param) {
        log.info("modifyDeviceGroup: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPutJsonGetStatusLine(
                    Constant.DEV_GROUP,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForModifyDeviceGroup.class);
        }
        log.info("modifyDeviceGroup, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.4 查询设备组详情
     */
    public static ResponseForQueryDeviceGroups queryDeviceGroups(@Required String appId, @Required String secret, @Optional RequestForQueryDeviceGroups param) {
        log.info("queryDeviceGroups: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.DEV_GROUP,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceGroups.class);
        }
        log.info("queryDeviceGroups, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.5 查询指定设备组
     */
    public static ResponseForQueryDeviceGroup queryDeviceGroup(@Required String appId, @Required String secret, @Required String devGroupId, @Optional String accessAppId) {
        log.info("queryDeviceGroup: appId={}, devGroupId={}, accessAppId={}", appId, devGroupId, accessAppId);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.DEV_GROUP + "/" + devGroupId + (StringUtils.isBlank(accessAppId) ? "" : ("?accessAppId=" + accessAppId)),
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceGroup.class);
        }
        log.info("queryDeviceGroup: appId={}, devGroupId={}, accessAppId={}", appId, devGroupId, accessAppId);
        return null;
    }

    /**
     * 2.9.6 查询指定设备组成员
     */
    public static ResponseForQueryDeviceFromDeviceGroup queryDeviceFromDeviceGroup(@Required String appId, @Required String secret, @Required RequestForQueryDeviceFromDeviceGroup param) {
        log.info("queryDeviceFromDeviceGroup: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.DEV_GROUP_DEVICE,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryDeviceFromDeviceGroup.class);
        }
        log.info("queryDeviceFromDeviceGroup, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.7 增加设备组成员
     */
    public static ResponseForAddDeviceToGroup addDeviceToGroup(@Required String appId, @Required String secret, @Required RequestForAddDeviceToGroup param) {
        log.info("addDeviceToGroup: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.DEV_GROUP_ADD_DEVICE + (StringUtils.isBlank(param.getAccessAppId()) ? "" : ("?accessAppId=" + param.getAccessAppId())),
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForAddDeviceToGroup.class);
        }
        log.info("addDeviceToGroup, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.9.8 删除设备组成员
     */
    public static boolean deleteDeviceFromGroup(@Required String appId, @Required String secret, @Required RequestForDeleteDeviceFromGroup param) {
        log.info("deleteDeviceFromGroup: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.DEV_GROUP_DELETE_DEVICE + (StringUtils.isBlank(param.getAccessAppId()) ? "" : ("?accessAppId=" + param.getAccessAppId())),
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse);
        }
        log.info("deleteDeviceFromGroup: appId={}, param={}", appId, param);
        return false;
    }

    /**
     * 2.10.1 查询版本包列表
     */
    public static ResponseForQueryPackages queryPackages(@Required String appId, @Required String secret, @Optional RequestForQueryPackages param) {
        log.info("queryPackages: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.PACKAGE,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryPackages.class);
        }
        log.info("queryPackages, result is null: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.10.2 查询指定版本号
     */
    public static ResponseForQueryPackage queryPackage(@Required String appId, @Required String secret, @Required String fieldId) {
        log.info("queryPackage: appId={}, fieldId={}", appId, fieldId);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.PACKAGE + "/" + fieldId,
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryPackage.class);
        }
        log.info("queryPackage, result is null: appId={}, fieldId={}", appId, fieldId);
        return null;
    }

    /**
     * 2.10.3 删除指定版本包
     */
    public static boolean deletePackage(@Required String appId, @Required String secret, @Required String fieldId) {
        log.info("deletePackage: appId={}, fieldId={}", appId, fieldId);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doDeleteGetStatusLine(
                    Constant.PACKAGE + "/" + fieldId,
                    buildHeader(appId, secret));

            return buildResult(httpResponse);
        }
        log.info("deletePackage: appId={}, fieldId={}", appId, fieldId);
        return false;
    }

    /**
     * 2.10.4 创建软件升级任务
     */
    public static ResponseForCreateSwUpgradeTask createSwUpgradeTask(@Required String appId, @Required String secret, @Required RequestForCreateSwUpgradeTask param) {
        log.info("createSwUpgradeTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.SOFTWARE_UPGRADE,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateSwUpgradeTask.class);
        }
        log.info("createSwUpgradeTask: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.10.5 创建固件升级任务
     */
    public static ResponseForCreateFwUpgradeTask createFwUpgradeTask(@Required String appId, @Required String secret, @Required RequestForCreateFwUpgradeTask param) {
        log.info("createFwUpgradeTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doPostJsonGetStatusLine(
                    Constant.SOFTWARE_UPGRADE,
                    buildHeader(appId, secret),
                    new Gson().toJson(param));

            return buildResult(httpResponse, ResponseForCreateFwUpgradeTask.class);
        }
        log.info("createFwUpgradeTask: appId={}, param={}", appId, param);
        return null;
    }

    /**
     * 2.10.6 查询指定升级任务结果
     */
    public static ResponseForQueryUpgradeResult queryUpgradeResult(@Required String appId, @Required String secret, @Required String operationId) {
        log.info("queryUpgradeResult: appId={}, operationId={}", appId, operationId);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.SOFTWARE_UPGRADE_RESULT + "/" + operationId,
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryUpgradeResult.class);
        }
        log.info("queryUpgradeResult: appId={}, operationId={}", appId, operationId);
        return null;
    }

    /**
     * 2.10.7 查询指定升级任务子任务详情
     */
    public static ResponseForQueryUpgradeTaskChildTask queryUpgradeTaskChildTask(@Required String appId, @Required String secret, @Required String operationId, @Optional RequestForQueryUpgradeTaskChildTask param) {
        log.info("queryUpgradeTaskChildTask: appId={}, operationId={}", appId, operationId);
        if (!StringUtils.isAnyBlank(appId, secret, operationId)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    String.format(Constant.SOFTWARE_UPGRADE_CHILD_TASK, operationId),
                    null,
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryUpgradeTaskChildTask.class);
        }
        log.info("queryUpgradeTaskChildTask: appId={}, operationId={}", appId, operationId);
        return null;
    }

    /**
     * 2.10.8 查询升级任务列表
     */
    public static ResponseForQueryUpgradeTask queryUpgradeTask(@Required String appId, @Required String secret, @Optional RequestForQueryUpgradeTask param) {
        log.info("queryUpgradeTask: appId={}, param={}", appId, param);
        if (!StringUtils.isAnyBlank(appId, secret)) {
            StreamClosedHttpResponse httpResponse = HttpsUtil.doGetWithParasGetStatusLine(
                    Constant.SOFTWARE_UPGRADE_RESULT,
                    buildParam(param),
                    buildHeader(appId, secret));

            return buildResult(httpResponse, ResponseForQueryUpgradeTask.class);
        }
        log.info("queryUpgradeTask: appId={}, param={}", appId, param);
        return null;
    }

    public static void main(String[] args) {
        String certPath = "outgoing.CertwithKey.pkcs12";
        String certPwd = "IoM@1234";
        String caPath = "ca.jks";
        String caPwd = "Huawei@123";
        NbiotApi.init(certPath, certPwd, caPath, caPwd);
        String appId = Constant.APPID, secret = Constant.SECRET;
        System.out.println(getToken(appId, secret));
//        ResponseForQueryAccessToken token = getToken(appId, secret);
//        System.out.println(refreshToken(appId, secret, token.getRefreshToken()));
//        System.out.println(getToken(appId, secret));
//        try {
//            Thread.sleep(3000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        System.out.println(getToken(appId, secret));
//        System.out.println(getToken(appId, secret));
//        queryDeviceCapabilities(appId, secret, Constant.DEVICE_ID, Constant.GATEWAY_ID);
//        System.out.println(queryDeviceData(appId, secret, Constant.DEVICE_ID));
//        System.out.println(queryAllDevices(appId, secret));

//        RequestForModifyDeviceInfo info = new RequestForModifyDeviceInfo();
//        info.setLocation("安徽合肥");
//        info.setMute(RequestForModifyDeviceInfo.MUTE.FALSE);
//        modifyDeviceInfo(appId, secret, Constant.DEVICE_ID, info);
//        System.out.println(queryDeviceActivationStatus(appId, secret, Constant.DEVICE_ID + "aaa"));
//        registerDirectlyConnectedDevice(appId, secret, "861234567891230");
//        System.out.println(deleteDirectlyConnectedDevice(appId, secret, "f6c17bd3-7144-442a-8d91-906d9d201f2c"));
    }

}

